Unit TokenIterator;

Interface

Uses
 Scanner,
 Sysutils;

Type
 EParser = Class(Exception);

 TTokenIterator = Class
 Private
  fCurrent, fMarked : Longint;
  fBuffer : TTokenList;
  Function GetCurrentToken : TToken;
 Public
  Constructor Create(Src : TTokenList);
  Function EOTk : Boolean;
  Procedure Start;
  Procedure Next;
  Procedure Back;
  Procedure Mark;
  Procedure BackTrack;
  Function Expected(aTokenType : TTokenKind; aHaltIfNotExpected : Boolean) : Boolean; Overload;
  Function Expected(aToken : String; aHaltIfNotExpected : Boolean) : Boolean; Overload;
  Function Expected(aTokens : Array Of String; aHaltIfNotExpected : Boolean) : Boolean; Overload;
  Function Consume(aTokenType : TTokenKind; aHaltIfNotExpected : Boolean) : Boolean; Overload;
  Function Consume(aToken : String; aHaltIfNotExpected : Boolean) : Boolean; Overload;
  Function Consume(aTokens : Array Of String; aHaltIfNotExpected : Boolean) : Boolean; Overload;
  Function Consume(aToken, aElse : String) : Boolean; Overload;
  Procedure RaiseError(Msg : String);
  Property Token : TToken Read GetCurrentToken;
 End;

Implementation

Function TTokenIterator.GetCurrentToken : TToken;
Begin
 GetCurrentToken := fBuffer[fCurrent];
End;

Constructor TTokenIterator.Create(Src : TTokenList);
Begin
 Inherited Create;
 fBuffer := Src;
 fCurrent := Low(fBuffer);
 fMarked := Low(fBuffer);
End;

Function TTokenIterator.EOTk : Boolean;
Begin
 EOTk := fCurrent > High(fBuffer);
End;

Procedure TTokenIterator.Start;
Begin
 fCurrent := Low(fBuffer);
End;

Procedure TTokenIterator.Next;
Begin
 Inc(fCurrent);
End;

Procedure TTokenIterator.Back;
Begin
 Dec(fCurrent);
End;

Procedure TTokenIterator.Mark;
Begin
 fMarked := fCurrent;
End;

Procedure TTokenIterator.BackTrack;
Begin
 fCurrent := fMarked;
End;

Function TTokenIterator.Expected(aTokenType : TTokenKind; aHaltIfNotExpected : Boolean) : Boolean;
Begin
	// Debug  WriteLn('Expected ', Ord(aTokenType), ' Got ', Ord(Token.Kind));
 Result := Token.Kind = aTokenType;
 If Not (Result) And aHaltIfNotExpected Then
  Case aTokenType Of
   tkUnknown :
    RaiseError('Expected unknown token (?).');
   tkWord :
    RaiseError('Expected reserved word (?).');
   tkIdent :
    RaiseError('Expected identifier.');
   tkNumber :
    RaiseError('Expected literal number.');
   tkString :
    RaiseError('Expected literal string.');
   tkBoolean :
    RaiseError('Expected literal boolean.');
   tkFloat :
    RaiseError('Expected literal float.');
   tkChar :
    RaiseError('Expected literal char.');
   tkComment :
    RaiseError('Expected comment (?).');
   tkPreCmd :
    RaiseError('Expected pre-processor command (?).');
  End;
End;

Function TTokenIterator.Expected(aToken : String; aHaltIfNotExpected : Boolean) : Boolean;
Begin
	// Debug WriteLn('Expected ', aToken, ' got ', Token.Value);
 Result := Token.Value = aToken;
 If Not (Result) And aHaltIfNotExpected Then
  RaiseError('Expected "' + aToken + '".');
End;

Function TTokenIterator.Expected(aTokens : Array Of String; aHaltIfNotExpected : Boolean) : Boolean;
Var
 lRow : Integer;
Begin
 Result := False;
 For lRow := Low(aTokens) To High(aTokens) Do
  Result := Result Or (Token.Value = aTokens[lRow]);
 If Not (Result) And aHaltIfNotExpected Then
  RaiseError('Expected "' + aTokens[Low(aTokens)] + '".');
End;

Function TTokenIterator.Consume(aTokenType : TTokenKind; aHaltIfNotExpected : Boolean) : Boolean;
Begin
 Result := Expected(aTokenType, aHaltIfNotExpected);
 If Result Then
  Next;
End;

Function TTokenIterator.Consume(aToken : String; aHaltIfNotExpected : Boolean) : Boolean;
Begin
 Result := Expected(aToken, aHaltIfNotExpected);
 If Result Then
  Next;
End;

Function TTokenIterator.Consume(aTokens : Array Of String; aHaltIfNotExpected : Boolean) : Boolean;
Begin
 Result := Expected(aTokens, aHaltIfNotExpected);
 If Result Then
  Next;
End;

Function TTokenIterator.Consume(aToken, aElse : String) : Boolean;
Begin
 Result := Consume(aToken, False);
 If Not (Result) Then
  Consume(aElse, True);
End;

Procedure TTokenIterator.RaiseError(Msg : String);
Begin
 Raise EParser.Create(
  'Error: (' +
  Token.SrcName + ', "' +
		Token.Value + '", ' +
  IntToStr(Token.Row) + ', ' +
  IntToStr(Token.Col) + ') ' +
  Msg);
End;

End.
